package me.hetong.caigou.ui.chessboard;

import javafx.application.Platform;
import javafx.geometry.VPos;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.text.TextAlignment;
import lombok.Data;
import me.hetong.caigou.Global;
import me.hetong.caigou.entity.Chess;
import me.hetong.caigou.entity.Zhao;
import me.hetong.caigou.util.FenUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 棋盘CANVAS
 *
 * @author hetong
 */
@Data
public class ChessboardForEngine extends Canvas {

    private GraphicsContext gc;
    private Integer gridSize = 40;// 每个方格的宽高
    private Integer crossPy = 2;// 十字交叉点偏移量
    private Integer crossLength = 8;// 十字交叉点线长度
    private Integer lineWidth = 1;// 默认线宽
    private Integer outLineWidth = 2;// 棋盘外边框线宽
    private Integer outLinePy = 4;// 棋盘外边框偏移量
    private String backgroundColor = Global.config.getBackgroundColorBoardInfer();
    private Image chuheImage = new Image("image/chessboard/ch.png");// 楚河图片
    private Image hanjieImage = new Image("image/chessboard/hj.png");// 汉界图片
    private Image ccImage = new Image("image/chessboard/to.png");// 选中图片
    private Image num1 = new Image("image/chessboard/1.png");// 选中图片
    private Image num2 = new Image("image/chessboard/2.png");// 选中图片
    private Image num3 = new Image("image/chessboard/3.png");// 选中图片
    private Image num4 = new Image("image/chessboard/4.png");// 选中图片
    private Map<String, Image> imageMap = new HashMap<>(36);
    private List<Chess> chessList = new ArrayList<>();
    private double radius = 16;
    private double radiusHalf = radius / 2;
    private Zhao zhao;// 当前走的着法
    private Zhao zhao1;// 推荐着法1
    private Zhao zhao2;// 推荐着法2
    private Zhao zhao3;// 推荐着法2
    private Zhao zhao4;// 推荐着法2
    private Chess click1;// 当前选择的棋子
    private Chess blank;// 当前选中的空白位置
    private boolean turnRed = true;

    public ChessboardForEngine(int size) {
        this.gridSize = size;
        this.setWidth(gridSize * 9 + gridSize / 2);
        this.setHeight(gridSize * 10 + gridSize / 2);
        this.gc = this.getGraphicsContext2D();

        // 初始化所有棋子
        chessList = FenUtils.fenToChessList(null);
        initImage();

        this.draw();

//        this.setOnMouseClicked(event -> {
//            if (event.getButton() == MouseButton.PRIMARY) {
//                ChessboardRightMenu.getInstance().hide();
//                leftClick(event);
//            }
//        });
    }

    /**
     * 初始化所有棋子图片
     */
    private void initImage() {
        for (Chess chess : chessList) {
            String s = (chess.getType() + chess.getK()).toLowerCase().replace("w", "r");
            String url = "image/chessboard/style/default/" + s + ".png";
            Image image = new Image(url);
            imageMap.put(chess.getType() + chess.getK(), image);
        }
    }

    private void setDefault() {
        this.gc.setTextAlign(TextAlignment.CENTER);
        this.gc.setTextBaseline(VPos.CENTER);
        this.gc.setFill(Paint.valueOf("#3d3d3d"));
        this.gc.setStroke(Paint.valueOf("#3d3d3d"));
//        Font font = new Font("serif", 12);
//        this.gc.setFont(font);
//        System.out.println(Font.getDefault().getName());
//        for (String fontName : Font.getFontNames()) {
//            System.out.println("名称" + fontName);
//        }
        Label label = new Label();
        label.setStyle("-fx-font-family: 'Arial'");
//        this.setStyle("-fx-font-family: 'serif'");
        gc.setFont(label.getFont());
    }

    public void draw() {
        this.setDefault();
        Platform.runLater(() -> {
            gc.clearRect(0, 0, this.getWidth(), this.getHeight());
            gc.setFill(Color.valueOf(backgroundColor));
            gc.fillRect(0, 0, this.getWidth(), this.getHeight());

            // 画横线
            for (int i = 0; i <= 9; i++) {
                drawLine(0, i, 8, i);
            }

            // 画竖线
            drawLine(0, 0, 0, 9);
            for (int i = 1; i <= 7; i++) {
                drawLine(i, 0, i, 4);
                drawLine(i, 5, i, 9);
            }
            drawLine(8, 0, 8, 9);

            // 画边框粗线
            drawBoardLine();

            // 画斜线叉
            drawLine(3, 0, 5, 2);
            drawLine(5, 0, 3, 2);
            drawLine(3, 7, 5, 9);
            drawLine(5, 7, 3, 9);

            // 画十字
            drawCross4(1, 2);
            drawCross4(7, 2);
            drawCross4(2, 3);
            drawCross4(4, 3);
            drawCross4(6, 3);
            drawCross4(2, 6);
            drawCross4(4, 6);
            drawCross4(6, 6);
            drawCross4(1, 7);
            drawCross4(7, 7);
            drawCross2L(0, 3);
            drawCross2L(0, 6);
            drawCross2R(8, 3);
            drawCross2R(8, 6);

//            for (int i = 0; i < 9; i++) {
//                drawTextTop(i, String.valueOf(i + 1));
//            }
//            drawTextBottom(0, "九");
//            drawTextBottom(1, "八");
//            drawTextBottom(2, "七");
//            drawTextBottom(3, "六");
//            drawTextBottom(4, "五");
//            drawTextBottom(5, "四");
//            drawTextBottom(6, "三");
//            drawTextBottom(7, "二");
//            drawTextBottom(8, "一");

            int py = (int) (gridSize / 2 * 9.5);
            double px = gridSize * 1.5;
            gc.drawImage(chuheImage, px, py, gridSize, gridSize);
            gc.drawImage(hanjieImage, (int) (this.getWidth() - gridSize - px), py, gridSize, gridSize);

            if (click1 != null) {
                int cx = (int) (click1.getX() * gridSize + gridSize / 2 * 1.5);
                int cy = (int) (click1.getY() * gridSize + gridSize / 2 * 1.5);
                drawImageCenter(ccImage, cx, cy, gridSize - 2, gridSize - 2);
                setDefault();
            }

            if (blank != null) {
                int cx = (int) (blank.getX() * gridSize + gridSize / 2 * 1.5);
                int cy = (int) (blank.getY() * gridSize + gridSize / 2 * 1.5);
                drawImageCenter(ccImage, cx, cy, gridSize - 2, gridSize - 2);
                setDefault();
            }

            if (zhao != null && zhao.getX1() != null) {
                int cx1 = (int) (zhao.getX1() * gridSize + gridSize / 2 * 1.5);
                int cy1 = (int) (zhao.getY1() * gridSize + gridSize / 2 * 1.5);
                int cx2 = (int) (zhao.getX2() * gridSize + gridSize / 2 * 1.5);
                int cy2 = (int) (zhao.getY2() * gridSize + gridSize / 2 * 1.5);
                drawImageCenter(ccImage, cx1, cy1, gridSize - 2, gridSize - 2);
                drawImageCenter(ccImage, cx2, cy2, gridSize - 2, gridSize - 2);
                setDefault();
            }

            for (Chess li : chessList) {
                Image image = imageMap.get(li.getType() + li.getK());
                drawImageCenter(image, (int) (li.getX() * gridSize + gridSize / 2 * 1.5), (int) (li.getY() * gridSize + gridSize / 2 * 1.5), gridSize, gridSize);
            }

            if (zhao1 != null) {
                drawEngiZhao(zhao1, "#336633", 1);
            }

            if (zhao2 != null) {
                drawEngiZhao(zhao2, "#0099cc", 2);
            }

            if (zhao3 != null) {
                drawEngiZhao(zhao3, "#9933ff", 3);
            }

            if (zhao4 != null) {
                drawEngiZhao(zhao4, "#996600", 4);
            }
        });
    }

    private void drawImageCenter(Image image, int cx, int cy, int w, int h) {
        gc.drawImage(image, cx - w / 2, cy - h / 2, w, h);
    }

    private void drawEngiZhao(Zhao zhao, String color, int number) {
        double fromX = (zhao.getX1() * gridSize + gridSize / 2 * 1.5);
        double fromY = (zhao.getY1() * gridSize + gridSize / 2 * 1.5);
        double toX = (zhao.getX2() * gridSize + gridSize / 2 * 1.5);
        double toY = (zhao.getY2() * gridSize + gridSize / 2 * 1.5);
        color += "ff";
        drawLineArrow2(fromX, fromY, toX, toY, color);
//        drawCircleNum(fromX, toX, fromY, toY, number);
        Image image = null;
        switch (number) {
            case 1:
                image = num1;
                break;
            case 2:
                image = num2;
                break;
            case 3:
                image = num3;
                break;
            case 4:
                image = num4;
                break;
        }
        if (image != null) {
            int wh = 14;
            double cx = (fromX + toX) / 2;
            double cy = (fromY + toY) / 2;

            gc.drawImage(image, cx - wh / 2, cy - wh / 2, wh, wh);
        }
    }

    private void drawCircleNum(double fromX, double toX, double fromY, double toY, String text) {
        double cx = (fromX + toX) / 2;
        double cy = (fromY + toY) / 2;
        gc.setFill(Paint.valueOf("#eee"));
        gc.fillOval(cx - radiusHalf, cy - radiusHalf, radius, radius);
        setDefault();
        gc.fillText(text, cx, cy);
    }

    /**
     * 画直线
     *
     * @param x1
     * @param y1
     * @param x2
     * @param y2
     */
    private void drawLine(int x1, int y1, int x2, int y2) {
        gc.strokeLine(x1 * gridSize + gridSize / 2 * 1.5, y1 * gridSize + gridSize / 2 * 1.5, x2 * gridSize + gridSize / 2 * 1.5, y2 * gridSize + gridSize / 2 * 1.5);
    }

    /**
     * 画棋盘十字
     *
     * @param x
     * @param y
     */
    private void drawCross4(int x, int y) {
        drawCross2L(x, y);
        drawCross2R(x, y);
    }

    /**
     * 画棋盘左半边十字
     *
     * @param x
     * @param y
     */
    private void drawCross2L(int x, int y) {
        // 中心点
        x = x * gridSize + gridSize / 2 + gridSize / 2 / 2;
        y = y * gridSize + gridSize / 2 + gridSize / 2 / 2;

        // 右上
        gc.strokeLine(x + crossPy, y - crossPy, x + crossPy + crossLength, y - crossPy);
        gc.strokeLine(x + crossPy, y - crossPy, x + crossPy, y - crossPy - crossLength);
        // 右下
        gc.strokeLine(x + crossPy, y + crossPy, x + crossPy + crossLength, y + crossPy);
        gc.strokeLine(x + crossPy, y + crossPy, x + crossPy, y + crossPy + crossLength);
    }

    /**
     * 画棋盘右半边十字
     *
     * @param x
     * @param y
     */
    private void drawCross2R(int x, int y) {
        // 中心点
        x = x * gridSize + gridSize / 2 + gridSize / 2 / 2;
        y = y * gridSize + gridSize / 2 + gridSize / 2 / 2;
        // 左上
        gc.strokeLine(x - crossPy, y - crossPy, x - crossPy - crossLength, y - crossPy);
        gc.strokeLine(x - crossPy, y - crossPy, x - crossPy, y - crossPy - crossLength);
        // 左下
        gc.strokeLine(x - crossPy, y + crossPy, x - crossPy - crossLength, y + crossPy);
        gc.strokeLine(x - crossPy, y + crossPy, x - crossPy, y + crossPy + crossLength);
    }

    private void drawTextTop(int x, String text) {
        gc.setFill(Color.valueOf("#3d3d3d"));
        gc.fillText(text, x * gridSize + gridSize / 2 * 1.5, 0 * gridSize + gridSize / 2 * 1.5 - 15);
    }

    private void drawTextBottom(int x, String text) {
        gc.fillText(text, x * gridSize + gridSize / 2 * 1.5, 9 * gridSize + gridSize / 2 * 1.5 + 15);
    }

    private void drawBoardLine() {
        gc.setLineWidth(outLineWidth);
        gc.strokeLine(0 * gridSize + gridSize / 2 * 1.5 - outLinePy, 0 * gridSize + gridSize / 2 * 1.5 - outLinePy, 8 * gridSize + gridSize / 2 * 1.5 + outLinePy, 0 * gridSize + gridSize / 2 * 1.5 - outLinePy);
        gc.strokeLine(0 * gridSize + gridSize / 2 * 1.5 - outLinePy, 0 * gridSize + gridSize / 2 * 1.5 - outLinePy, 0 * gridSize + gridSize / 2 * 1.5 - outLinePy, 9 * gridSize + gridSize / 2 * 1.5 + outLinePy);
        gc.strokeLine(0 * gridSize + gridSize / 2 * 1.5 - outLinePy, 9 * gridSize + gridSize / 2 * 1.5 + outLinePy, 8 * gridSize + gridSize / 2 * 1.5 + outLinePy, 9 * gridSize + gridSize / 2 * 1.5 + outLinePy);
        gc.strokeLine(8 * gridSize + gridSize / 2 * 1.5 + outLinePy, 0 * gridSize + gridSize / 2 * 1.5 - outLinePy, 8 * gridSize + gridSize / 2 * 1.5 + outLinePy, 9 * gridSize + gridSize / 2 * 1.5 + outLinePy);
        gc.setLineWidth(lineWidth);
    }

    private void drawArrow(double fromX, double fromY, double toX, double toY, String color) {

        int theta = 30;
        int headlen = 10;
        int width = 3;

        // 计算各角度和对应的P2,P3坐标
        double angle = Math.atan2(fromY - toY, fromX - toX) * 180 / Math.PI,
                angle1 = (angle + theta) * Math.PI / 180,
                angle2 = (angle - theta) * Math.PI / 180,
                topX = headlen * Math.cos(angle1),
                topY = headlen * Math.sin(angle1),
                botX = headlen * Math.cos(angle2),
                botY = headlen * Math.sin(angle2);

        gc.save();
        gc.beginPath();

        double arrowX = fromX - topX;
        double arrowY = fromY - topY;

        gc.moveTo(arrowX, arrowY);
        gc.moveTo(fromX, fromY);
        gc.lineTo(toX, toY);
        arrowX = toX + topX;
        arrowY = toY + topY;
        gc.moveTo(arrowX, arrowY);
        gc.lineTo(toX, toY);
        arrowX = toX + botX;
        arrowY = toY + botY;
        gc.lineTo(arrowX, arrowY);
        gc.setStroke(Paint.valueOf(color));
        gc.setLineWidth(width);
        gc.stroke();
        gc.restore();
    }

    public void setClick1(Chess click1) {
        this.click1 = click1;
        draw();
    }

    public void setZhao(Zhao zhao) {
        this.zhao = zhao;
        draw();
    }

    public void setZhao1(Zhao zhao1) {
        this.zhao1 = zhao1;
        draw();
    }

    public void setZhao2(Zhao zhao2) {
        this.zhao2 = zhao2;
        draw();
    }

    public void setZhao3(Zhao zhao) {
        this.zhao3 = zhao;
        draw();
    }

    public void setZhao4(Zhao zhao) {
        this.zhao4 = zhao;
        draw();
    }

    public void setBlank(Chess blank) {
        this.blank = blank;
        draw();
    }

    public void setChessList(List<Chess> chessList) {
        if (chessList == null) {
            this.chessList = FenUtils.fenToChessList(null);
        } else {
            this.chessList = chessList;
        }
    }

    public void setChessList(String fen) {
        this.chessList = FenUtils.fenToChessList(fen);
        draw();
    }

    /**
     * @param {*canvas context 对象} ctx
     * @param {*起点横坐标} fromX
     * @param {*起点纵坐标} fromY
     * @param {*终点横坐标} toX
     * @param {*终点纵坐标} toY
     *                 以下注释以终点在坐标第一象限内，且方向为右上方
     */
    private void drawLineArrow2(double fromX, double fromY, double toX, double toY, String color) {
        double headlen = (0.2 * 1.41 * Math.sqrt((fromX - toX) * (fromX - toX) + (fromY - toY) * (fromY - toY)));//箭头头部长度
        headlen = headlen > 40 ? 40 : headlen;//40是箭头头部最大值
        double theta = 30;//自定义箭头线与直线的夹角
        double arrowX, arrowY;//箭头线终点坐标
        // 计算各角度和对应的箭头终点坐标
        double angle = (Math.atan2(fromY - toY, fromX - toX) * 180 / Math.PI);
        double angle1 = ((angle + theta) * Math.PI / 180);
        double angle2 = ((angle - theta) * Math.PI / 180);
        double topX = (headlen * Math.cos(angle1));
        double topY = (headlen * Math.sin(angle1));
        double botX = (headlen * Math.cos(angle2));
        double botY = (headlen * Math.sin(angle2));
        boolean toLeft = fromX > toX;
        boolean toUp = fromY > toY;

        //箭头最上点
        arrowX = toX + topX;
        arrowY = toY + topY;
        //箭头下拐点
        double arrowX1 = toX + botX;
        double arrowY1 = toY + botY;
        //箭头上拐点
        double arrowX2 = (toUp ? arrowX + 0.25 * Math.abs(arrowX1 - arrowX) : arrowX - 0.25 * Math.abs(arrowX1 - arrowX));
        double arrowY2 = (toLeft ? arrowY - 0.25 * Math.abs(arrowY1 - arrowY) : arrowY + 0.25 * Math.abs(arrowY1 - arrowY));
        //箭头最下点 
        double arrowX3 = (toUp ? arrowX + 0.75 * Math.abs(arrowX1 - arrowX) : arrowX - 0.75 * Math.abs(arrowX1 - arrowX));
        double arrowY3 = (toLeft ? arrowY - 0.75 * Math.abs(arrowY1 - arrowY) : arrowY + 0.75 * Math.abs(arrowY1 - arrowY));

        gc.beginPath();
        //起点-起点，闭合
        gc.moveTo(fromX, fromY);
        gc.lineTo(arrowX2, arrowY2);
        gc.lineTo(arrowX, arrowY);
        gc.lineTo(toX, toY);

        gc.lineTo(arrowX1, arrowY1);
        gc.lineTo(arrowX3, arrowY3);
        gc.lineTo(fromX, fromY);
        gc.closePath();
        gc.setFill(Paint.valueOf(color));
        gc.setStroke(Paint.valueOf("#ffffff00"));
        gc.fill();
//        gc.stroke();

        setDefault();
    }

    public void initUI() {
        this.blank = null;
        this.click1 = null;
        this.zhao1 = null;
        this.zhao2 = null;
        this.zhao3 = null;
        this.zhao4 = null;
        this.zhao = null;
        this.draw();
    }
}